<?php

declare(strict_types=1);

namespace SixShop\System\Service;

use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RuntimeException;
use SixShop\Core\Helper;
use SixShop\Core\Service\CoreService;
use think\facade\Log;

/**
 * 前端代码部署服务
 * 
 * 负责插件前端代码的自动部署和清理
 */
class FrontendDeployService
{
    /**
     * 部署前端代码
     * 
     * @param string $extensionId 插件ID
     * @return bool 是否部署成功
     */
    public function deploy(string $extensionId): bool
    {
        try {
            // 1. 检查前端代码是否存在
            if (!$this->hasFrontendCode($extensionId)) {
                Log::info("插件 {$extensionId} 没有前端代码，跳过部署");
                return true; // 跳过，不算失败
            }

            // 2. 获取源目录和目标目录
            $sourcePath = $this->getFrontendSourcePath($extensionId);
            $targetPath = $this->getFrontendTargetPath();

            // 3. 检查目标目录是否已存在
            $pluginTargetPath = $targetPath . '/' . $extensionId;
            if (is_dir($pluginTargetPath)) {
                Log::warning("目标目录已存在，将覆盖：{$pluginTargetPath}");
                $this->removeDirectory($pluginTargetPath);
            }

            // 4. 复制前端代码
            $this->copyDirectory($sourcePath, $targetPath);

            // 5. 记录部署信息
            $this->logDeploy($extensionId, [
                'source_path' => $sourcePath,
                'target_path' => $targetPath,
                'status' => 'success'
            ]);

            Log::info("前端代码部署成功：{$extensionId}");
            return true;

        } catch (\Exception $e) {
            Log::error("前端代码部署失败：{$extensionId}，错误：" . $e->getMessage());

            // 回滚：删除已复制的文件
            if (isset($pluginTargetPath) && is_dir($pluginTargetPath)) {
                $this->removeDirectory($pluginTargetPath);
            }

            // 不抛出异常，允许安装继续
            return false;
        }
    }

    /**
     * 移除前端代码
     * 
     * @param string $extensionId 插件ID
     * @return bool 是否移除成功
     */
    public function remove(string $extensionId): bool
    {
        try {
            // 兼容性处理：检查插件是否有前端代码
            // 如果插件没有前端代码（旧项目），则不删除 admin 的前端代码
            if (!$this->hasFrontendCode($extensionId)) {
                Log::info("插件 {$extensionId} 没有前端代码，跳过删除（兼容旧项目）");
                return true;
            }
            
            $targetPath = $this->getFrontendTargetPath();
            $pluginTargetPath = $targetPath . '/' . $extensionId;

            if (!is_dir($pluginTargetPath)) {
                Log::info("前端代码不存在，无需删除：{$extensionId}");
                return true;
            }

            // 删除目录
            $this->removeDirectory($pluginTargetPath);

            // 记录删除信息
            $this->logRemove($extensionId);

            Log::info("前端代码删除成功：{$extensionId}");
            return true;

        } catch (\Exception $e) {
            Log::error("前端代码删除失败：{$extensionId}，错误：" . $e->getMessage());
            return false;
        }
    }

    /**
     * 检查插件是否有前端代码
     * 
     * @param string $extensionId 插件ID
     * @return bool
     */
    private function hasFrontendCode(string $extensionId): bool
    {
        try {
            $frontendPath = $this->getFrontendSourcePath($extensionId);
        } catch (\Exception $e) {
            Log::warning("获取插件路径失败：{$extensionId}，错误：" . $e->getMessage());
            return false;
        }

        // 检查目录是否存在
        if (!is_dir($frontendPath)) {
            return false;
        }

        // 检查是否有插件名称的子目录
        $pluginFrontendPath = $frontendPath . '/' . $extensionId;
        if (!is_dir($pluginFrontendPath)) {
            Log::warning("插件 {$extensionId} 前端代码目录结构不正确，应为：frontend/{$extensionId}/");
            return false;
        }

        return true;
    }

    /**
     * 获取插件的实际路径
     * 
     * @param string $extensionId 插件ID
     * @return string
     * @throws RuntimeException
     */
    private function getPluginPath(string $extensionId): string
    {
        // 方法 1: 使用 Helper::extension_path()
        $path = Helper::extension_path($extensionId);
        if (is_dir($path)) {
            return $path;
        }

        // 方法 2: 从 CoreService 获取 Composer 映射
        if (isset(CoreService::$extensionComposerMap[$extensionId])) {
            $composerInfo = CoreService::$extensionComposerMap[$extensionId];
            $vendorPath = base_path('vendor/' . $composerInfo['name']);
            if (is_dir($vendorPath)) {
                return $vendorPath;
            }
        }

        // 方法 3: 手动检测常见路径
        $possiblePaths = [
            base_path('runtime/extension/' . $extensionId),
            base_path('vendor/six-shop/' . $extensionId),
            base_path('vendor/sixdec/' . $extensionId),
        ];

        foreach ($possiblePaths as $path) {
            if (is_dir($path)) {
                return $path;
            }
        }

        throw new RuntimeException("找不到插件路径：{$extensionId}");
    }

    /**
     * 获取前端代码源路径
     * 
     * @param string $extensionId 插件ID
     * @return string
     */
    private function getFrontendSourcePath(string $extensionId): string
    {
        $pluginPath = $this->getPluginPath($extensionId);
        return $pluginPath . '/frontend';
    }

    /**
     * 获取前端代码目标路径
     * 
     * @return string
     */
    private function getFrontendTargetPath(): string
    {
        // base_path() 返回 backend 目录
        // 需要回到项目根目录
        $backendPath = base_path();
        $projectRoot = dirname($backendPath);
        $realRoot = dirname($projectRoot);
        return $realRoot . '/frontend/admin/src/views';
    }

    /**
     * 递归复制目录
     * 
     * @param string $source 源目录
     * @param string $target 目标目录
     * @return void
     */
    private function copyDirectory(string $source, string $target): void
    {
        // 递归复制文件
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::SELF_FIRST
        );

        foreach ($iterator as $item) {
            // 计算目标路径
            $subPath = $iterator->getSubPathName();
            $targetPath = $target . DIRECTORY_SEPARATOR . $subPath;

            if ($item->isDir()) {
                // 创建目录
                if (!is_dir($targetPath)) {
                    mkdir($targetPath, 0755, true);
                }
            } else {
                // 复制文件
                $targetDir = dirname($targetPath);
                if (!is_dir($targetDir)) {
                    mkdir($targetDir, 0755, true);
                }
                // 转换 SplFileInfo 对象为字符串路径
                copy($item->getPathname(), $targetPath);
            }
        }
    }

    /**
     * 递归删除目录
     * 
     * @param string $path 目录路径
     * @return void
     */
    private function removeDirectory(string $path): void
    {
        if (!is_dir($path)) {
            return;
        }

        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::CHILD_FIRST
        );

        foreach ($iterator as $item) {
            if ($item->isDir()) {
                rmdir($item->getPathname());
            } else {
                unlink($item->getPathname());
            }
        }

        rmdir($path);
    }

    /**
     * 记录部署信息
     * 
     * @param string $extensionId 插件ID
     * @param array $info 部署信息
     * @return void
     */
    private function logDeploy(string $extensionId, array $info): void
    {
        $logDir = runtime_path('frontend_deploy');
        if (!is_dir($logDir)) {
            mkdir($logDir, 0755, true);
        }

        $logFile = $logDir . '/deployed.json';

        // 读取现有记录
        $deployed = [];
        if (file_exists($logFile)) {
            $content = file_get_contents($logFile);
            $deployed = json_decode($content, true) ?: [];
        }

        // 添加新记录
        if (!isset($deployed['deployed'])) {
            $deployed['deployed'] = [];
        }

        $deployed['deployed'][] = array_merge([
            'extension_id' => $extensionId,
            'deployed_at' => date('Y-m-d H:i:s'),
        ], $info);

        // 写入文件
        file_put_contents(
            $logFile,
            json_encode($deployed, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
        );
    }

    /**
     * 记录删除信息
     * 
     * @param string $extensionId 插件ID
     * @return void
     */
    private function logRemove(string $extensionId): void
    {
        $logDir = runtime_path('frontend_deploy');
        if (!is_dir($logDir)) {
            mkdir($logDir, 0755, true);
        }

        $logFile = $logDir . '/deployed.json';

        // 读取现有记录
        $deployed = [];
        if (file_exists($logFile)) {
            $content = file_get_contents($logFile);
            $deployed = json_decode($content, true) ?: [];
        }

        // 添加删除记录
        if (!isset($deployed['removed'])) {
            $deployed['removed'] = [];
        }

        $deployed['removed'][] = [
            'extension_id' => $extensionId,
            'removed_at' => date('Y-m-d H:i:s'),
        ];

        // 写入文件
        file_put_contents(
            $logFile,
            json_encode($deployed, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
        );
    }
}
